package repository

import (
	"context"
	"database/sql"
	"fmt"
	"strings"

	"mall/common/modelx"
	"mall/service/forum/model"

	"github.com/sirupsen/logrus"
	"github.com/volatiletech/null/v8"
	"github.com/volatiletech/sqlboiler/v4/boil"
	"github.com/volatiletech/sqlboiler/v4/queries/qm"
	"github.com/zeromicro/go-zero/core/stores/cache"
)

type (
	// ForumUserRepository is an interface to be customized, add more methods here,
	// and implement the added methods in customForumUserRepository.
	ForumUserRepository interface {
		Conn() error
		GetClickLogs(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]interface{},
		) ([]*model.ForumUserClickLog, int64, error)
		GetSearchLogs(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]interface{},
		) ([]*model.ForumUserSearchLog, int64, error)
		GetFeeds(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]interface{},
		) ([]*model.ForumFeed, int64, error)
		InsertClickLog(
			ctx context.Context,
			log *model.ForumUserClickLog,
		) error
		InsertSearchLog(
			ctx context.Context,
			log *model.ForumUserSearchLog,
		) int64
		UpdateSearchLogBatch(ctx context.Context, ids []int64, cols model.M) (int64, error)
		ForceDeleteSearchLogBatch(ctx context.Context, ids []int64) (int64, error)
		InsertFeed(ctx context.Context, feed *model.ForumFeed) error                   /////
		UpdateFeedBatch(ctx context.Context, ids []int64, cols model.M) (int64, error) /////
		ForceDeleteFeedBatch(ctx context.Context, ids []int64) (int64, error)          /////
		GetNotices(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]interface{},
		) ([]*model.ForumUserNotice, int64, error)
		GetPageSetting(ctx context.Context, key string) (string, error)
		SetPageSetting(ctx context.Context, key string, setting string) (int64, error)
		UpdateCollect(
			ctx context.Context,
			item *model.ForumUserCollect,
		) (int64, error)
		UpdateCollectBatch(
			ctx context.Context,
			cols model.M,
			filter map[string]map[string][]interface{},
		) (int64, error)
		GetCollects(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]interface{},
		) ([]*model.ForumUserCollect, int64, error)
		UpdateShowcase(
			ctx context.Context,
			item *model.ForumUserShowcase,
			extra *model.ForumExtra,
		) (int64, error)
		GetShowcases(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]interface{},
		) ([]*model.ForumUserShowcase, int64, error)
	}

	customForumUserRepository struct {
		cacheConf  cache.CacheConf
		dataSource string

		mysqlConn *sql.DB
	}
)

// NewForumUserRepository returns a repository for the database table.
func NewForumUserRepository(dataSource string, cacheConf cache.CacheConf) ForumUserRepository {
	return &customForumUserRepository{
		cacheConf:  cacheConf,
		dataSource: dataSource,
	}
}

func (r *customForumUserRepository) Conn() error {
	if r.mysqlConn == nil {
		mysqlConn, err := modelx.NewMysqlConn(r.dataSource)
		if err != nil {
			return err
		}

		r.mysqlConn = mysqlConn
	}

	return nil
}

func (r *customForumUserRepository) GetClickLogs(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]interface{},
) (list []*model.ForumUserClickLog, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var offset int
	var limit int
	var selectCol string
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "offset":
			if val, ok := v.(int32); ok && val > 0 {
				offset = int(val)
			}
		case "limit":
			if val, ok := v.(int32); ok && val > 0 {
				limit = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.ForumUserClickLogColumns.ClickLogID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserClickLogColumns.ClickLogID, opMap)...)
			case model.ForumUserClickLogColumns.UserID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserClickLogColumns.UserID, opMap)...)
			case model.ForumUserClickLogColumns.PlatformID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserClickLogColumns.PlatformID, opMap)...)
			case model.ForumUserClickLogColumns.SearchLogID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserClickLogColumns.SearchLogID, opMap)...)
			case model.ForumUserClickLogColumns.ObjectID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserClickLogColumns.ObjectID, opMap)...)
			case model.ForumUserClickLogColumns.ObjectType:
				mods = append(mods, modelx.GetIntMods(model.ForumUserClickLogColumns.ObjectType, opMap)...)
			case model.ForumUserClickLogColumns.Status:
				mods = append(mods, modelx.GetIntMods(model.ForumUserClickLogColumns.Status, opMap)...)
			}
		}
	}

	if withCount >= 0 {
		if withCount >= 2 {
			var nextCount int64
			var previousCount int64
			subMods := make([]qm.QueryMod, len(mods), len(mods)+3)
			copy(subMods, mods)
			subMods = append(subMods, qm.Limit(1))
			subMods = append(subMods, qm.Select(model.ForumUserClickLogColumns.ClickLogID))

			if withCount != 3 && offset >= 1 {
				subMods = append(subMods, qm.Offset(offset-1))
				previousList, previousErr := model.ForumUserClickLogs(subMods...).All(ctx, r.mysqlConn)
				if previousErr != nil {
					err = previousErr
					return
				}
				if len(previousList) > 0 {
					previousCount = 1
				}
			}
			if limit > 0 {
				subMods = append(subMods, qm.Offset(offset+limit))
				nextList, nextErr := model.ForumUserClickLogs(subMods...).All(ctx, r.mysqlConn)
				if nextErr != nil {
					err = nextErr
					return
				}
				if len(nextList) > 0 {
					nextCount = 1
				}
			}

			count = previousCount + nextCount*2
		} else {
			count, err = model.ForumUserClickLogs(mods...).Count(ctx, r.mysqlConn)
			if err != nil {
				return
			}

			if withCount == 0 {
				return
			}
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	} else if limit > 0 || offset > 0 {
		if limit > 0 {
			mods = append(mods, qm.Limit(limit))
		}
		if offset > 0 {
			mods = append(mods, qm.Offset(offset))
		}
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.ForumUserClickLogColumns.ClickLogID)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.ForumUserClickLogs(mods...).All(ctx, r.mysqlConn)
	return
}

func (r *customForumUserRepository) GetSearchLogs(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]interface{},
) (list []*model.ForumUserSearchLog, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var selectCol string
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.ForumUserSearchLogColumns.SearchLogID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserSearchLogColumns.SearchLogID, opMap)...)
			case model.ForumUserSearchLogColumns.UserID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserSearchLogColumns.UserID, opMap)...)
			case model.ForumUserSearchLogColumns.PlatformID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserSearchLogColumns.PlatformID, opMap)...)
			case model.ForumUserSearchLogColumns.Status:
				mods = append(mods, modelx.GetIntMods(model.ForumUserSearchLogColumns.Status, opMap)...)
			}
		}
	}

	if withCount >= 0 {
		count, err = model.ForumUserSearchLogs(mods...).Count(ctx, r.mysqlConn)
		if err != nil {
			return
		}

		if withCount == 0 {
			return
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.ForumUserSearchLogColumns.SearchLogID)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.ForumUserSearchLogs(mods...).All(ctx, r.mysqlConn)
	return
}

func (r *customForumUserRepository) GetFeeds(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]interface{},
) (list []*model.ForumFeed, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var offset int
	var limit int
	var selectCol string
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "offset":
			if val, ok := v.(int32); ok && val > 0 {
				offset = int(val)
			}
		case "limit":
			if val, ok := v.(int32); ok && val > 0 {
				limit = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.ForumFeedColumns.ID:
				mods = append(mods, modelx.GetIntMods(model.ForumFeedColumns.ID, opMap)...)
			case model.ForumFeedColumns.UserID:
				mods = append(mods, modelx.GetIntMods(model.ForumFeedColumns.UserID, opMap)...)
			case model.ForumFeedColumns.ForumID:
				mods = append(mods, modelx.GetIntMods(model.ForumFeedColumns.ForumID, opMap)...)
			case model.ForumFeedColumns.TopicID:
				mods = append(mods, modelx.GetIntMods(model.ForumFeedColumns.TopicID, opMap)...)
			case model.ForumFeedColumns.PostID:
				mods = append(mods, modelx.GetIntMods(model.ForumFeedColumns.PostID, opMap)...)
			case model.ForumFeedColumns.AuthorID:
				mods = append(mods, modelx.GetIntMods(model.ForumFeedColumns.AuthorID, opMap)...)
			case model.ForumFeedColumns.AuthorNickname:
				mods = append(mods, modelx.GetStringMods(model.ForumFeedColumns.AuthorNickname, opMap)...)
			case model.ForumFeedColumns.Status:
				mods = append(mods, modelx.GetIntMods(model.ForumFeedColumns.Status, opMap)...)
			case model.ForumFeedColumns.Sticky:
				mods = append(mods, modelx.GetIntMods(model.ForumFeedColumns.Sticky, opMap)...)
			case model.ForumFeedColumns.LikeCount:
				mods = append(mods, modelx.GetIntMods(model.ForumFeedColumns.LikeCount, opMap)...)
			case model.ForumFeedColumns.ReplyCount:
				mods = append(mods, modelx.GetIntMods(model.ForumFeedColumns.ReplyCount, opMap)...)
			}
		}
	}

	if withCount >= 0 {
		if withCount >= 2 {
			var nextCount int64
			var previousCount int64
			subMods := make([]qm.QueryMod, len(mods), len(mods)+3)
			copy(subMods, mods)
			subMods = append(subMods, qm.Limit(1))
			subMods = append(subMods, qm.Select(model.ForumFeedColumns.ID))

			if withCount != 3 && offset >= 1 {
				subMods = append(subMods, qm.Offset(offset-1))
				previousList, previousErr := model.ForumFeeds(subMods...).All(ctx, r.mysqlConn)
				if previousErr != nil {
					err = previousErr
					return
				}

				if len(previousList) > 0 {
					previousCount = 1
				}
			}
			if limit > 0 {
				subMods = append(subMods, qm.Offset(offset+limit))
				nextList, nextErr := model.ForumFeeds(subMods...).All(ctx, r.mysqlConn)
				if nextErr != nil {
					err = nextErr
					return
				}

				if len(nextList) > 0 {
					nextCount = 1
				}
			}

			count = previousCount + nextCount*2
		} else {
			count, err = model.ForumFeeds(mods...).Count(ctx, r.mysqlConn)
			if err != nil {
				return
			}

			if withCount == 0 {
				return
			}
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	} else if limit > 0 || offset > 0 {
		if limit > 0 {
			mods = append(mods, qm.Limit(limit))
		}
		if offset > 0 {
			mods = append(mods, qm.Offset(offset))
		}
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.ForumFeedColumns.ID)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.ForumFeeds(mods...).All(ctx, r.mysqlConn)
	return
}

func (r *customForumUserRepository) InsertClickLog(
	ctx context.Context,
	log *model.ForumUserClickLog,
) error {
	if err := r.Conn(); err != nil {
		return err
	}

	return log.Insert(ctx, r.mysqlConn, boil.Infer())
}

func (r *customForumUserRepository) InsertSearchLog(
	ctx context.Context,
	log *model.ForumUserSearchLog,
) int64 {
	if err := r.Conn(); err != nil {
		return 0
	}

	err := log.Insert(ctx, r.mysqlConn, boil.Infer())
	if err != nil {
		return 0
	}

	return int64(log.SearchLogID)
}

func (r *customForumUserRepository) UpdateSearchLogBatch(ctx context.Context, ids []int64, cols model.M) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	if len(ids) > 0 {
		values := make([]interface{}, 0, len(ids))
		for _, id := range ids {
			values = append(values, uint64(id))
		}

		mods = append(mods, qm.WhereIn(fmt.Sprintf("%s IN ?", model.ForumUserSearchLogColumns.SearchLogID), values...))
	}

	rowsAff, err = model.ForumUserSearchLogs(mods...).UpdateAll(ctx, r.mysqlConn, cols)
	return
}

func (r *customForumUserRepository) ForceDeleteSearchLogBatch(ctx context.Context, ids []int64) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	if len(ids) > 0 {
		values := make([]interface{}, 0, len(ids))
		for _, id := range ids {
			values = append(values, id)
		}

		mods = append(mods, qm.WhereIn(fmt.Sprintf("%s IN ?", model.ForumUserSearchLogColumns.SearchLogID), values...))
	}

	rowsAff, err = model.ForumUserSearchLogs(mods...).DeleteAll(ctx, r.mysqlConn)
	return
}

func (r *customForumUserRepository) InsertFeed(
	ctx context.Context,
	feed *model.ForumFeed,
) error {
	if err := r.Conn(); err != nil {
		return err
	}

	return feed.Insert(ctx, r.mysqlConn, boil.Infer())
}

func (r *customForumUserRepository) UpdateFeedBatch(ctx context.Context, ids []int64, cols model.M) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	if len(ids) > 0 {
		values := make([]interface{}, 0, len(ids))
		for _, id := range ids {
			values = append(values, uint64(id))
		}

		mods = append(mods, qm.WhereIn(fmt.Sprintf("%s IN ?", model.ForumFeedColumns.ID), values...))
	}

	rowsAff, err = model.ForumFeeds(mods...).UpdateAll(ctx, r.mysqlConn, cols)
	return
}

func (r *customForumUserRepository) ForceDeleteFeedBatch(ctx context.Context, ids []int64) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	if len(ids) > 0 {
		values := make([]interface{}, 0, len(ids))
		for _, id := range ids {
			values = append(values, id)
		}

		mods = append(mods, qm.WhereIn(fmt.Sprintf("%s IN ?", model.ForumFeedColumns.ID), values...))
	}

	rowsAff, err = model.ForumFeeds(mods...).DeleteAll(ctx, r.mysqlConn)
	return
}

func (r *customForumUserRepository) GetNotices(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]interface{},
) (list []*model.ForumUserNotice, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var offset int
	var limit int
	var selectCol string
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "offset":
			if val, ok := v.(int32); ok && val > 0 {
				offset = int(val)
			}
		case "limit":
			if val, ok := v.(int32); ok && val > 0 {
				limit = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.ForumUserNoticeColumns.NoticeID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserNoticeColumns.NoticeID, opMap)...)
			case model.ForumUserNoticeColumns.UserID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserNoticeColumns.UserID, opMap)...)
			case model.ForumUserNoticeColumns.ParentID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserNoticeColumns.ParentID, opMap)...)
			case model.ForumUserNoticeColumns.ForumID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserNoticeColumns.ForumID, opMap)...)
			case model.ForumUserNoticeColumns.TopicID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserNoticeColumns.TopicID, opMap)...)
			case model.ForumUserNoticeColumns.PostID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserNoticeColumns.PostID, opMap)...)
			case model.ForumUserNoticeColumns.CommentID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserNoticeColumns.CommentID, opMap)...)
			case model.ForumUserNoticeColumns.Type:
				mods = append(mods, modelx.GetIntMods(model.ForumUserNoticeColumns.Type, opMap)...)
			case model.ForumUserNoticeColumns.Status:
				mods = append(mods, modelx.GetIntMods(model.ForumUserNoticeColumns.Status, opMap)...)
			}
		}
	}

	if withCount >= 0 {
		if withCount >= 2 {
			var nextCount int64
			var previousCount int64
			subMods := make([]qm.QueryMod, len(mods), len(mods)+3)
			copy(subMods, mods)
			subMods = append(subMods, qm.Limit(1))
			subMods = append(subMods, qm.Select(model.ForumUserNoticeColumns.NoticeID))

			if withCount != 3 && offset >= 1 {
				subMods = append(subMods, qm.Offset(offset-1))
				previousList, previousErr := model.ForumUserNotices(subMods...).All(ctx, r.mysqlConn)
				if previousErr != nil {
					err = previousErr
					return
				}

				if len(previousList) > 0 {
					previousCount = 1
				}
			}
			if limit > 0 {
				subMods = append(subMods, qm.Offset(offset+limit))
				nextList, nextErr := model.ForumUserNotices(subMods...).All(ctx, r.mysqlConn)
				if nextErr != nil {
					err = nextErr
					return
				}

				if len(nextList) > 0 {
					nextCount = 1
				}
			}

			count = previousCount + nextCount*2
		} else {
			count, err = model.ForumUserNotices(mods...).Count(ctx, r.mysqlConn)
			if err != nil {
				return
			}

			if withCount == 0 {
				return
			}
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	} else if limit > 0 || offset > 0 {
		if limit > 0 {
			mods = append(mods, qm.Limit(limit))
		}
		if offset > 0 {
			mods = append(mods, qm.Offset(offset))
		}
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.ForumUserNoticeColumns.NoticeID)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.ForumUserNotices(mods...).All(ctx, r.mysqlConn)
	return
}

func (r *customForumUserRepository) GetPageSetting(ctx context.Context, key string) (setting string, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	mods = append(mods, model.ForumForumMetumWhere.MetaKey.EQ(key))
	list, err := model.ForumForumMeta(mods...).All(ctx, r.mysqlConn)
	if len(list) > 0 {
		metum := list[0]
		if metum.MetaValue.Valid {
			setting = metum.MetaValue.String
		}
	}

	return
}

func (r *customForumUserRepository) SetPageSetting(ctx context.Context, key string, setting string) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	mods = append(mods, model.ForumForumMetumWhere.MetaKey.EQ(key))
	list, err := model.ForumForumMeta(mods...).All(ctx, r.mysqlConn)
	if len(list) > 0 {
		metum := list[0]
		if len(setting) > 0 {
			metum.MetaValue = null.StringFrom(setting)
			rowsAff, err = metum.Update(ctx, r.mysqlConn, boil.Blacklist(
				model.ForumForumMetumColumns.MetaID,
				model.ForumForumMetumColumns.ForumID,
			))
		} else {
			rowsAff, err = metum.Delete(ctx, r.mysqlConn)
		}
	} else {
		metum := &model.ForumForumMetum{
			ForumID:   1,
			MetaKey:   key,
			MetaValue: null.StringFrom(setting),
		}
		err = metum.Insert(ctx, r.mysqlConn, boil.Infer())
	}

	return
}

func (r *customForumUserRepository) UpdateCollect(
	ctx context.Context,
	item *model.ForumUserCollect,
) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	mods = append(mods, model.ForumUserCollectWhere.UserID.EQ(item.UserID))
	mods = append(mods, model.ForumUserCollectWhere.PlatformID.EQ(item.PlatformID))
	mods = append(mods, model.ForumUserCollectWhere.ObjectID.EQ(item.ObjectID))
	mods = append(mods, model.ForumUserCollectWhere.ObjectType.EQ(item.ObjectType))
	list, listErr := model.ForumUserCollects(mods...).All(ctx, r.mysqlConn)
	if listErr != nil {
		logrus.Info(fmt.Sprintf("UpdateCollect error, err: %+v", listErr))
		if listErr == sql.ErrNoRows {
			item.CreatedAt = item.UpdatedAt // item 不指定CreatedAt，避免被修改
			err = item.Insert(ctx, r.mysqlConn, boil.Infer())
			return 1, err
		}

		return 0, listErr
	}

	if len(list) == 0 {
		item.CreatedAt = item.UpdatedAt // item 不指定CreatedAt，避免被修改
		err = item.Insert(ctx, r.mysqlConn, boil.Infer())
		return 1, err
	}

	rowsAff, err = model.ForumUserCollects(mods...).UpdateAll(ctx, r.mysqlConn, model.M{
		model.ForumUserCollectColumns.Status:       item.Status,
		model.ForumUserCollectColumns.SorterValue1: item.SorterValue1,
		model.ForumUserCollectColumns.SorterValue2: item.SorterValue2,
		model.ForumUserCollectColumns.SorterValue3: item.SorterValue3,
		model.ForumUserCollectColumns.SorterValue4: item.SorterValue4,
		model.ForumUserCollectColumns.SorterValue5: item.SorterValue5,
		model.ForumUserCollectColumns.FilterValue1: item.FilterValue1,
		model.ForumUserCollectColumns.FilterValue2: item.FilterValue2,
		model.ForumUserCollectColumns.FilterValue3: item.FilterValue3,
		model.ForumUserCollectColumns.FilterValue4: item.FilterValue4,
		model.ForumUserCollectColumns.FilterValue5: item.FilterValue5,
		model.ForumUserCollectColumns.UpdatedAt:    item.UpdatedAt,
	})

	return
}

func (r *customForumUserRepository) UpdateCollectBatch(
	ctx context.Context,
	cols model.M,
	filter map[string]map[string][]interface{},
) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.ForumUserCollectColumns.CollectID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserCollectColumns.CollectID, opMap)...)
			case model.ForumUserCollectColumns.UserID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserCollectColumns.UserID, opMap)...)
			case model.ForumUserCollectColumns.PlatformID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserCollectColumns.PlatformID, opMap)...)
			case model.ForumUserCollectColumns.ObjectID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserCollectColumns.ObjectID, opMap)...)
			case model.ForumUserCollectColumns.ObjectType:
				mods = append(mods, modelx.GetIntMods(model.ForumUserCollectColumns.ObjectType, opMap)...)
			case model.ForumUserCollectColumns.Status:
				mods = append(mods, modelx.GetIntMods(model.ForumUserCollectColumns.Status, opMap)...)
			}
		}
	}
	if len(mods) == 0 {
		return
	}

	rowsAff, err = model.ForumUserCollects(mods...).UpdateAll(ctx, r.mysqlConn, cols)
	return
}

func (r *customForumUserRepository) GetCollects(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]interface{},
) (list []*model.ForumUserCollect, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var offset int
	var limit int
	var selectCol string
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "offset":
			if val, ok := v.(int32); ok && val > 0 {
				offset = int(val)
			}
		case "limit":
			if val, ok := v.(int32); ok && val > 0 {
				limit = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.ForumUserCollectColumns.CollectID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserCollectColumns.CollectID, opMap)...)
			case model.ForumUserCollectColumns.UserID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserCollectColumns.UserID, opMap)...)
			case model.ForumUserCollectColumns.PlatformID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserCollectColumns.PlatformID, opMap)...)
			case model.ForumUserCollectColumns.ObjectID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserCollectColumns.ObjectID, opMap)...)
			case model.ForumUserCollectColumns.ObjectType:
				mods = append(mods, modelx.GetIntMods(model.ForumUserCollectColumns.ObjectType, opMap)...)
			case model.ForumUserCollectColumns.Status:
				mods = append(mods, modelx.GetIntMods(model.ForumUserCollectColumns.Status, opMap)...)
			}
		}
	}

	if withCount >= 0 {
		if withCount >= 2 {
			var nextCount int64
			var previousCount int64
			subMods := make([]qm.QueryMod, len(mods), len(mods)+3)
			copy(subMods, mods)
			subMods = append(subMods, qm.Limit(1))
			subMods = append(subMods, qm.Select(model.ForumUserCollectColumns.CollectID))

			if withCount != 3 && offset >= 1 {
				subMods = append(subMods, qm.Offset(offset-1))
				previousList, previousErr := model.ForumUserCollects(subMods...).All(ctx, r.mysqlConn)
				if previousErr != nil {
					err = previousErr
					return
				}

				if len(previousList) > 0 {
					previousCount = 1
				}
			}
			if limit > 0 {
				subMods = append(subMods, qm.Offset(offset+limit))
				nextList, nextErr := model.ForumUserCollects(subMods...).All(ctx, r.mysqlConn)
				if nextErr != nil {
					err = nextErr
					return
				}

				if len(nextList) > 0 {
					nextCount = 1
				}
			}

			count = previousCount + nextCount*2
		} else {
			count, err = model.ForumUserCollects(mods...).Count(ctx, r.mysqlConn)
			if err != nil {
				return
			}

			if withCount == 0 {
				return
			}
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	} else if limit > 0 || offset > 0 {
		if limit > 0 {
			mods = append(mods, qm.Limit(limit))
		}
		if offset > 0 {
			mods = append(mods, qm.Offset(offset))
		}
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.ForumUserCollectColumns.CollectID)
		columns = append(columns, model.ForumUserCollectColumns.SorterValue1)
		columns = append(columns, model.ForumUserCollectColumns.SorterValue2)
		columns = append(columns, model.ForumUserCollectColumns.SorterValue3)
		columns = append(columns, model.ForumUserCollectColumns.SorterValue4)
		columns = append(columns, model.ForumUserCollectColumns.SorterValue5)
		columns = append(columns, model.ForumUserCollectColumns.FilterValue1)
		columns = append(columns, model.ForumUserCollectColumns.FilterValue2)
		columns = append(columns, model.ForumUserCollectColumns.FilterValue3)
		columns = append(columns, model.ForumUserCollectColumns.FilterValue4)
		columns = append(columns, model.ForumUserCollectColumns.FilterValue5)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.ForumUserCollects(mods...).All(ctx, r.mysqlConn)
	return
}

func (r *customForumUserRepository) UpdateShowcase(
	ctx context.Context,
	item *model.ForumUserShowcase,
	extra *model.ForumExtra,
) (int64, error) {
	if err := r.Conn(); err != nil {
		return 0, err
	}

	tx, err := r.mysqlConn.BeginTx(ctx, nil)
	if err != nil {
		return 0, err
	}

	if item != nil {
		var mods []qm.QueryMod
		mods = append(mods, model.ForumUserShowcaseWhere.UserID.EQ(item.UserID))
		mods = append(mods, model.ForumUserShowcaseWhere.PlatformID.EQ(item.PlatformID))
		list, listErr := model.ForumUserShowcases(mods...).All(ctx, r.mysqlConn)
		if listErr != nil {
			logrus.Info(fmt.Sprintf("UpdateShowcase error, err: %+v", listErr))
			if listErr == sql.ErrNoRows {
				item.CreatedAt = item.UpdatedAt // item 不指定CreatedAt，避免被修改
				err = item.Insert(ctx, tx, boil.Infer())
				if err != nil {
					tx.Rollback()
					return 0, err
				}

				tx.Commit()
				return int64(item.ShowcaseID), nil
			}

			return 0, listErr
		}

		if len(list) == 0 {
			item.CreatedAt = item.UpdatedAt // item 不指定CreatedAt，避免被修改
			err = item.Insert(ctx, tx, boil.Infer())
			if err != nil {
				tx.Rollback()
				return 0, err
			}

			tx.Commit()
			return int64(item.ShowcaseID), nil
		}

		_, err = model.ForumUserShowcases(mods...).UpdateAll(ctx, tx, model.M{
			model.ForumUserShowcaseColumns.Background:  item.Background,
			model.ForumUserShowcaseColumns.Pattern:     item.Pattern,
			model.ForumUserShowcaseColumns.Frame:       item.Frame,
			model.ForumUserShowcaseColumns.Description: item.Description,
			model.ForumUserShowcaseColumns.UpdatedAt:   item.UpdatedAt,
		})
		if err != nil {
			tx.Rollback()
			return 0, err
		}

		tx.Commit()
		return int64(list[0].ShowcaseID), nil
	}

	if extra != nil {
		var rowsAff int64
		if len(extra.Media) > 0 {
			for _, m := range extra.Media {
				if m.AttachmentRelationshipID > 0 {
					_, err = m.Update(ctx, tx, boil.Blacklist(
						model.ForumAttachmentRelationshipColumns.AttachmentRelationshipID,
						model.ForumAttachmentRelationshipColumns.ObjectID,
						model.ForumAttachmentRelationshipColumns.ObjectType,
						model.ForumAttachmentRelationshipColumns.AttachmentID,
					))
				} else {
					err = m.Insert(ctx, tx, boil.Infer())
				}
				if err != nil {
					tx.Rollback()
					return 0, err
				}
			}
		}
		if len(extra.DelMediaIds) > 0 {
			var mods []qm.QueryMod
			mods = append(mods, model.ForumAttachmentRelationshipWhere.AttachmentRelationshipID.IN(extra.DelMediaIds))
			rowsAff, err = model.ForumAttachmentRelationships(mods...).DeleteAll(ctx, tx)
			if err != nil {
				tx.Rollback()
				return 0, err
			}
		}

		tx.Commit()
		return rowsAff, err
	}

	return 0, nil
}

func (r *customForumUserRepository) GetShowcases(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]interface{},
) (list []*model.ForumUserShowcase, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var selectCol string
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.ForumUserShowcaseColumns.ShowcaseID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserShowcaseColumns.ShowcaseID, opMap)...)
			case model.ForumUserShowcaseColumns.UserID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserShowcaseColumns.UserID, opMap)...)
			case model.ForumUserShowcaseColumns.PlatformID:
				mods = append(mods, modelx.GetIntMods(model.ForumUserShowcaseColumns.PlatformID, opMap)...)
			}
		}
	}

	if withCount >= 0 {
		count, err = model.ForumUserShowcases(mods...).Count(ctx, r.mysqlConn)
		if err != nil {
			return
		}

		if withCount == 0 {
			return
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.ForumUserShowcaseColumns.ShowcaseID)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.ForumUserShowcases(mods...).All(ctx, r.mysqlConn)
	return
}
